/* src/interfaces/ecpg/ecpglib/error.c */

#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"

#include "ecpgerrno.h"
#include "ecpglib.h"
#include "ecpglib_extern.h"
#include "ecpgtype.h"
#include "sqlca.h"

void ecpg_raise(int fc_line, int fc_code, const char *fc_sqlstate, const char *fc_str)
{
	struct sqlca_t *fc_sqlca = ECPGget_sqlca();

	if (fc_sqlca == NULL)
	{
		ecpg_log("out of memory");
		ECPGfree_auto_mem();
		return;
	}

	fc_sqlca->sqlcode = fc_code;
	strncpy(fc_sqlca->sqlstate, fc_sqlstate, sizeof(fc_sqlca->sqlstate));

	switch (fc_code)
	{
		case ECPG_NOT_FOUND:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("no data found on line %d"), fc_line);
			break;

		case ECPG_OUT_OF_MEMORY:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("out of memory on line %d"), fc_line);
			break;

		case ECPG_UNSUPPORTED:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("unsupported type \"%s\" on line %d"), fc_str, fc_line);
			break;

		case ECPG_TOO_MANY_ARGUMENTS:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("too many arguments on line %d"), fc_line);
			break;

		case ECPG_TOO_FEW_ARGUMENTS:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("too few arguments on line %d"), fc_line);
			break;

		case ECPG_INT_FORMAT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("invalid input syntax for type int: \"%s\", on line %d"), fc_str, fc_line);
			break;

		case ECPG_UINT_FORMAT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("invalid input syntax for type unsigned int: \"%s\", on line %d"), fc_str, fc_line);
			break;

		case ECPG_FLOAT_FORMAT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("invalid input syntax for floating-point type: \"%s\", on line %d"), fc_str, fc_line);
			break;

		case ECPG_CONVERT_BOOL:
			if (fc_str)
				snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
				/*------
				   翻译者：此字符串将在149个字符扩展处被截断。 */
						 ecpg_gettext("invalid syntax for type boolean: \"%s\", on line %d"), fc_str, fc_line);
			else
				snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
				/*------
				   翻译者：此字符串将在149个字符扩展处被截断。 */
						 ecpg_gettext("could not convert boolean value: size mismatch, on line %d"), fc_line);
			break;

		case ECPG_EMPTY:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("empty query on line %d"), fc_line);
			break;

		case ECPG_MISSING_INDICATOR:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("null value without indicator on line %d"), fc_line);
			break;

		case ECPG_NO_ARRAY:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("variable does not have an array type on line %d"), fc_line);
			break;

		case ECPG_DATA_NOT_ARRAY:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("data read from server is not an array on line %d"), fc_line);
			break;

		case ECPG_ARRAY_INSERT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("inserting an array of variables is not supported on line %d"), fc_line);
			break;

		case ECPG_NO_CONN:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("connection \"%s\" does not exist on line %d"), fc_str, fc_line);
			break;

		case ECPG_NOT_CONN:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("not connected to connection \"%s\" on line %d"), fc_str, fc_line);
			break;

		case ECPG_INVALID_STMT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("invalid statement name \"%s\" on line %d"), fc_str, fc_line);
			break;

		case ECPG_UNKNOWN_DESCRIPTOR:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("descriptor \"%s\" not found on line %d"), fc_str, fc_line);
			break;

		case ECPG_INVALID_DESCRIPTOR_INDEX:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("descriptor index out of range on line %d"), fc_line);
			break;

		case ECPG_UNKNOWN_DESCRIPTOR_ITEM:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("unrecognized descriptor item \"%s\" on line %d"), fc_str, fc_line);
			break;

		case ECPG_VAR_NOT_NUMERIC:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("variable does not have a numeric type on line %d"), fc_line);
			break;

		case ECPG_VAR_NOT_CHAR:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("variable does not have a character type on line %d"), fc_line);
			break;

		case ECPG_TRANS:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("error in transaction processing on line %d"), fc_line);
			break;

		case ECPG_CONNECT:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("could not connect to database \"%s\" on line %d"), fc_str, fc_line);
			break;

		default:
			snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc),
			/*------
			   翻译者：此字符串将在149个字符扩展处被截断。 */
					 ecpg_gettext("SQL error %d on line %d"), fc_code, fc_line);
			break;
	}

	fc_sqlca->sqlerrm.sqlerrml = strlen(fc_sqlca->sqlerrm.sqlerrmc);
	ecpg_log("raising sqlcode %d on line %d: %s\n", fc_code, fc_line, fc_sqlca->sqlerrm.sqlerrmc);

	/*
		 * 如果连接中断，我们可能会来到这里，所以我们检查
		 * 这个，而不是仅仅给出通用的内部错误
		 */
	ECPGfree_auto_mem();
}

void ecpg_raise_backend(int fc_line, PGresult *fc_result, PGconn *fc_conn, int fc_compat)
{
	struct sqlca_t *fc_sqlca = ECPGget_sqlca();
	char	   *fc_sqlstate;
	char	   *fc_message;

	if (fc_sqlca == NULL)
	{
		ecpg_log("out of memory");
		ECPGfree_auto_mem();
		return;
	}

	/* 复制错误消息 */
	fc_sqlstate = PQresultErrorField(fc_result, PG_DIAG_SQLSTATE);
	if (fc_sqlstate == NULL)
		fc_sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
	fc_message = PQresultErrorField(fc_result, PG_DIAG_MESSAGE_PRIMARY);
	if (fc_message == NULL)
		fc_message = PQerrorMessage(fc_conn);

	if (strcmp(fc_sqlstate, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR) == 0)
	{
		/* 复制SQLSTATE */
		if (PQstatus(fc_conn) == CONNECTION_BAD)
		{
			fc_sqlstate = "57P02";
			fc_message = ecpg_gettext("the connection to the server was lost");
		}
	}

	/* 为了向后兼容分配 SQLCODE */  
	snprintf(fc_sqlca->sqlerrm.sqlerrmc, sizeof(fc_sqlca->sqlerrm.sqlerrmc), "%s on line %d", fc_message, fc_line);
	fc_sqlca->sqlerrm.sqlerrml = strlen(fc_sqlca->sqlerrm.sqlerrmc);

	/* 释放我们为用户分配的所有内存 */  
	strncpy(fc_sqlca->sqlstate, fc_sqlstate, sizeof(fc_sqlca->sqlstate));

	/* 过滤掉所有错误代码 */  
	if (strncmp(fc_sqlca->sqlstate, "23505", sizeof(fc_sqlca->sqlstate)) == 0)
		fc_sqlca->sqlcode = INFORMIX_MODE(fc_compat) ? ECPG_INFORMIX_DUPLICATE_KEY : ECPG_DUPLICATE_KEY;
	else if (strncmp(fc_sqlca->sqlstate, "21000", sizeof(fc_sqlca->sqlstate)) == 0)
		fc_sqlca->sqlcode = INFORMIX_MODE(fc_compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_SUBSELECT_NOT_ONE;
	else
		fc_sqlca->sqlcode = ECPG_PGSQL;

	ecpg_log("raising sqlstate %.*s (sqlcode %ld): %s\n",
			 (int) sizeof(fc_sqlca->sqlstate), fc_sqlca->sqlstate, fc_sqlca->sqlcode, fc_sqlca->sqlerrm.sqlerrmc);

	/*
		 * 如果连接中断，我们可能会来到这里，所以我们检查
		 * 这个，而不是仅仅给出通用的内部错误
		 */
	ECPGfree_auto_mem();
}

/* 打印出错误信息 */  
bool ecpg_check_PQresult(PGresult *fc_results, int fc_lineno, PGconn *fc_connection, enum COMPAT_MODE fc_compat)
{
	if (fc_results == NULL)
	{
		ecpg_log("ecpg_check_PQresult on line %d: no result - %s", fc_lineno, PQerrorMessage(fc_connection));
		ecpg_raise_backend(fc_lineno, NULL, fc_connection, fc_compat);
		return false;
	}

	switch (PQresultStatus(fc_results))
	{

		case PGRES_TUPLES_OK:
			return true;
			break;
		case PGRES_EMPTY_QUERY:
			/* 不执行任何操作 */
			ecpg_raise(fc_lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
			PQclear(fc_results);
			return false;
			break;
		case PGRES_COMMAND_OK:
			return true;
			break;
		case PGRES_NONFATAL_ERROR:
		case PGRES_FATAL_ERROR:
		case PGRES_BAD_RESPONSE:
			ecpg_log("ecpg_check_PQresult on line %d: bad response - %s", fc_lineno, PQresultErrorMessage(fc_results));
			ecpg_raise_backend(fc_lineno, fc_results, fc_connection, fc_compat);
			PQclear(fc_results);
			return false;
			break;
		case PGRES_COPY_OUT:
			return true;
			break;
		case PGRES_COPY_IN:
			ecpg_log("ecpg_check_PQresult on line %d: COPY IN data transfer in progress\n", fc_lineno);
			PQendcopy(fc_connection);
			PQclear(fc_results);
			return false;
			break;
		default:
			ecpg_log("ecpg_check_PQresult on line %d: unknown execution status type\n",
					 fc_lineno);
			ecpg_raise_backend(fc_lineno, fc_results, fc_connection, fc_compat);
			PQclear(fc_results);
			return false;
			break;
	}
}

/* print out an error message */
void sqlprint(void)
{
	struct sqlca_t *fc_sqlca = ECPGget_sqlca();

	if (fc_sqlca == NULL)
	{
		ecpg_log("out of memory");
		return;
	}

	fc_sqlca->sqlerrm.sqlerrmc[fc_sqlca->sqlerrm.sqlerrml] = '\0';
	fprintf(stderr, ecpg_gettext("SQL error: %s\n"), fc_sqlca->sqlerrm.sqlerrmc);
}
